package com.ficus.road.maintain.handler.monitor;

import com.ficus.road.maintain.core.model.Confirmation;
import com.ficus.road.maintain.core.model.Hit;
import com.ficus.road.maintain.core.model.SourceEnum;
import com.ficus.road.maintain.dao.HitDao;
import com.ficus.road.maintain.dto.Checklist;
import com.ficus.road.maintain.dto.ChecklistOfCar;
import com.ficus.road.maintain.dto.ChecklistOfEvent;
import com.ficus.road.maintain.dto.TotalStatistic;
import com.ficus.road.maintain.util.FormatUtil;
import com.ficus.road.maintain.util.MyDateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.core.annotation.Order;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author xiawen yang
 * @date 2022/6/2 下午8:49
 */
@Component
@Order(3)
@Slf4j
@RequiredArgsConstructor
public class EventMonitorHandler extends AbstractMonitorHandler {
    private final HitDao hitDao;

    @Override
    Checklist doFilter(Checklist checklist) {
        log.info("事件监测统计开始");
        long start = System.currentTimeMillis();
        Date date = DateUtils.addDays(new Date(), -1);
        Date startOfDay = MyDateUtil.getStartOfDay(date);
        List<ChecklistOfEvent> checklistOfEvents = new ArrayList<>();
        Query query = new Query(Criteria.where("first_hit_time").gte(startOfDay.getTime() / 1000));
        List<Hit> allHits = hitDao.findByQuery(query);
        Map<String, List<Hit>> hitTypeMap = allHits.stream().collect(Collectors.groupingBy(Hit::getType));
        //总数统计: 总检出病害(发现病害), 总展示病害(审核通过的病害)
        TotalStatistic totalStatistic = new TotalStatistic();
        int totalToday = (int) hitDao.count(new Query(Criteria.where("attrs.source").is(SourceEnum.NORMAL.toString()).and("first_hit_time").gte(MyDateUtil.getStartOfDay(new Date()).getTime() / 1000)));
        int totalCorrectToday = (int) hitDao.count(new Query(Criteria.where("attrs.source").is(SourceEnum.NORMAL.toString())
                .and("attrs.confirmation.status").is(Confirmation.ConfirmationStatus.CORRECT).and("first_hit_time").gte(MyDateUtil.getStartOfDay(new Date()).getTime() / 1000)));
        totalStatistic.setTotalNewHits(totalToday);
        totalStatistic.setTotalCheckHits(totalCorrectToday);
        //总数统计: 总里程数
        double totalMiles = checklist.getCarList().stream().mapToDouble(ChecklistOfCar::getMiles).sum();
        totalStatistic.setTotalMiles(FormatUtil.keepDecimalsOfK(totalMiles, 2));
        //总数统计: 总运行时间
        int totalRuntime = checklist.getCarList().stream().mapToInt(ChecklistOfCar::getCloudCarTotalMinute).sum();
        totalStatistic.setTotalRuntime(FormatUtil.keepDecimalsOfK((double) totalRuntime / 60, 2));
        checklist.setTotalStatistic(totalStatistic);

        hitTypeMap.forEach((type, hits) -> {
            int total = hits.size();
            int tagHitNum = (int) hits.stream().filter(hit -> hit.getAttrs().getSource().equals("TAG")).count();
            int normalHitNum = (int) hits.stream().filter(hit -> hit.getAttrs().getSource().equals("NORMAL")).count();
            int totalPassHitNum = (int) hits.stream().filter(hit -> hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.CORRECT) &&
                    hit.getAttrs().getSource().equals(SourceEnum.NORMAL.toString())).count();
            int uncheckHitNum = (int) hits.stream().filter(hit -> hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.TO_BE_CONFIRMED)).count();
            double checkRate = total == 0 ? 0 : FormatUtil.keepDecimalsOfK((double) (total - uncheckHitNum) / (double) total, 2);
            // 百公里新增病害数(总里程数为0时不统计百公里病害数)
            int newOfHMile = totalMiles == 0 ? 0 : (int) (normalHitNum * 100 / totalMiles);
            // 百公里审核通过数(总里程数为0时不统计百公里审核通过数)
            int passOfHMile = totalMiles == 0 ? 0 : (int) (totalPassHitNum * 100 / totalMiles);
            //准确率 = normal类型且审核通过的病害 / normal类型的总病害数
            int passHitNum = (int) hits.stream().filter(hit -> hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.CORRECT) &&
                    hit.getAttrs().getSource().equals(SourceEnum.NORMAL.toString())).count();
            double passRate = normalHitNum == 0 ? 0 : FormatUtil.keepDecimalsOfK((double) passHitNum / (double) normalHitNum, 2);
            ChecklistOfEvent checklistOfEvent = ChecklistOfEvent.builder().eventType(type).total(total).tagHitNum(tagHitNum).normalHitNum(normalHitNum)
                    .passHitNum(totalPassHitNum).uncheckHitNum(uncheckHitNum).checkRate(checkRate)
                    .newHitNumOfHMile(newOfHMile).passHitNumOfHMile(passOfHMile).passRate(passRate).build();
            checklistOfEvents.add(checklistOfEvent);
        });
        checklist.setEventList(checklistOfEvents);
        checklistDao.saveOrUpdate(checklist);
        log.info("时间监测统计耗时： {} ms", System.currentTimeMillis() - start);
        return checklist;
    }
}
